<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
/**
 * CodeIgniter ACL Class
 *
 * ACL library for CodeIgniter Framework
 *
 * @package		CodeIgniter
 * @subpackage	Libraries
 * @category	Libraries
 * @author 		David Brandes <david.brandes at gmail.com>
 * @link 		https://github.com/brandesign/CodeIgniter-ACL
 * @copyright 	Copyright (c) 2012, David Brandes
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

class Acl_auth
{
	/**
	 * List of all errors
	 *
	 * @var array
	 */
	private $_errors = array();
	private $_messages = array();
	private $_config;
    private $_user_id;
    private $_isLoggedAdmin = false; // Flag to tell that I logging in as admin or not
    private $_update = array(); // List of data to update
    //const PASSWORD_EXPIRY = 60; // IN minutes For Testing only
    const PASSWORD_EXPIRY = 86400; // Expiry By Day


    public function __construct()
	{

		$this->load->config('acl_auth', TRUE);
		$this->_config = $this->config->item('acl_auth');
		$this->load->library( array( 'email', 'phpass','session') );
		$this->load->helper('cookie');
		$this->load->model( $this->_config['user_model'], 'user_model' );
        $this->load->model('user_roles_model','user_roles_model');
        $this->load->model('user_password_model', 'UPM');
        $this->load->model('audit_model');
		$this->lang->load('acl_auth');
		if( ! $this->logged_in() && get_cookie('identity') && get_cookie('remember_code') )
		{
			$this->login_remembered();
		}
	}

	/**
	* __get
	*
	* Enables the use of CI super-global without having to define an extra variable.
	*
	* @access public
	* @param $var
	* @return mixed
	*/
	public function __get( $var )
	{
		return get_instance()->$var;
	}

	/**
	 * register a new user
	 *
	 * @access public
	 * @param array
	 * @return bool
	 * @todo set error messages
	 **/
	public function register( $data, $role = null )
	{
		if(!array_key_exists($this->_config['identity_field'], $data) 
           OR !array_key_exists( $this->_config['password_field'], $data ) )
		{
			$this->set_error( 'register_failed' );
			return false;
		}
        
        // Password and user must not same.
        if ($data[$this->_config['password_field']] == $data[$this->_config['identity_field']])
        {
            $this->set_error('user_password_same');
            return false;
        }

		$insert = array();
        $user = $this->user_model->get_user($data[$this->_config['identity_field']]);
        if ((!$data['id']) && $user){
            $this->set_error( 'msg_user_exist', "{username}", $user->account_name);
            return false;
        }



        // Validate the fields.
        log_message('debug','DATA: '.print_r($data,1));
		foreach( $data as $field => $value ){
			if( $this->user_model->field_exists( $field )){
                if( $field == $this->_config['password_field']){
                    //if ($data['id'] && !trim($value)) continue; // Skip updating password
                    if ($value) $insert[$field] = $this->phpass->hash( $value );
                }else{
                    $insert[$field] = $value;
                }
			}
		}
        
        log_message('debug','FiltereData: '.print_r($insert,1));
        if ($data['id'] ==''){
            $this->load->library( array( 'configuration'));
            
            $insert['timestamp'] = time();
            $insert['pass_expired'] = $insert['timestamp']+$this->configuration->getPasswordExpiration()*self::PASSWORD_EXPIRY;
            
            $id = $this->user_model->insert( $insert );
            $this->set_message('account_created');
            try{
                $msg = 'ADD '.($role=='1'?'Admin User ':'User ').'{'.$data['account_name'].'}';
                log_message('info', 'AUDIT ==> '.$msg);
                $this->audit_model->save(Audit_model::ADD,$msg);
            }  catch (Exception $e){
                
                
            }

            if( $id ){
                // @win? Why she was login after create the account?
                //$this->login( $data['email'], $data['password'], TRUE );
                if ($role != null){
                    // assign the user as USER role
                    $roles=array(
                        'roles_id'=> $role,
                        'users_id'=> $id);

                    log_message('debug','Added role for userID('.$id.')'.
                    $this->user_roles_model->insert($roles));
                }
                return $id;
            }else{
                $this->set_error('register_failed');
                return false;
            }
        }else{
            log_message('info','UPDATE ('.$data['id'].')');
            log_message('info',print_r($insert,1));
            unset($insert['id']);
            if ($user && $user->id){
                // s
                try{
                    $changes = "\n";
                    foreach($insert as $key => $value){
                        if($key != $this->_config['password_field']){
                            // Never log Password Changes.
                            if ($user->$key != $value){
                                $changes .= $user->$key.' => '.$value."\n";
                            }
                        }else{
                            log_message('debug', "Skip updating Password");
                        }
                    }
                    
                    
                    if (0){
                        // Disable the ability to promote user into admin.
                        // 1:admin 2:user 3;superadmin
                        $_roles = array(1=>'admin', 2=>'user', 3=>'superadmin');
                        $ojbRole = $this->user_model->get_role($user->id);
                        if ($ojbRole){
                            log_message('debug', "Role: ".print_r($ojbRole, true));
                        }
                        if ($ojbRole){
                            if ($ojbRole->roles_id != $role){
                                $changes .= 'Role('.$_roles[$ojbRole->roles_id].') => Role('.$_roles[$role].')';
                                $roles=array('roles_id'=> $role);

                                $this->user_roles_model->update($ojbRole->ur_id, $roles);
                            }
                        }else{
                            // Add new role.
                            $roles=array(
                                'roles_id'=> $role,
                                'users_id'=> $user->id);

                            log_message('debug','Added role for userID('.$id.')'.
                            $this->user_roles_model->insert($roles));
                        }
                    }
                    $msg = 'UPDATE '.$user->id.'-'.$user->account_name."\n".
                            $changes;
                    log_message('info', 'AUDIT ==> '.$msg);
                    $this->audit_model->save(Audit_model::UPDATE, $msg);
                }  catch (Exception $e){
                    
                }
            }
            
            $id = $this->user_model->update($data['id'], $insert);
            $this->set_message('account_update');
            if($id){
                
                return $id;
            }
        }
	}

    /**
     * Delete the file.
     * 
     * @param int $id
     * @return boolean
     */
	public function delete($id)
	{
        log_message('info', 'Deleting '.$id);
        $user = null;
        if ((int)$id){
            $user = $this->user_model->get_by('id',$id);
        }else{
            $user = $this->user_model->get_by('account_name',$id);
        }
        
        if ($user && $user->id){
            log_message('info', 'AUDIT Deleting '.$user->id.'-'.$user->account_name);
            $this->audit_model->save(Audit_model::DELETE, 'DELETE '.$user->id.'-'.$user->account_name);
            
            $this->user_model->delete($user->id);
            $this->set_message('account_deleted');
            // @TODO, I think need to delete his/her session(s) first.
            
            return true;
        }
        return false;
	}

    
	/**
	 * login
	 *
	 * @access public
	 * @param string $identity username
	 * @param string $password plain password
	 * @param bool $remember tell to remember of not
	 * @param array $session_data 
	 * @return bool
     * 
     * @TODO, Create fields of login attempt. for stable login attempt counts.
	 **/
    public function login( $identity, $password, $remember = FALSE, $session_data = array() )
    {
        $user = $this->user_model->get_user( $identity );
        $json_attempt = array(0);
        $login_attempt = ($user)?strtolower($user->account_name):'login_attempt';
        $utime = time();

        if (!$user){
            $this->set_error( 'login_failed' );
            return false;
        }

        if ($user){
            if ($user->login_expired > $utime){
                // happen when account have currently login on other server.
                $this->_user_id=$user->id;
                log_message('info', __METHOD__.' -> User currently login');
                $this->set_error('msg_login_active'); // User currently login
                return false;
            }else if (!$user->status){
                $this->set_error('account_inactive'); // User currently login
                return false;                
            }
        }
        
        
        $json_attempt = $this->session->userdata($login_attempt);
        log_message("debug",__METHOD__." -> Attempt DATA{".$json_attempt."}: ");
        $json_attempt = $json_attempt?json_decode($json_attempt, true):array();
        $attempt = isset($json_attempt['att'])?($json_attempt['att']+1):1;
        $exp = isset($json_attempt['exp'])?$json_attempt['exp']:1;
        log_message("debug",__METHOD__." -> Log_attempt{".$login_attempt."}: ".$attempt);
        

        
		if( ! $user OR ! $this->phpass->check( $password, $user->password ) )
		{
            //$json_attempt = is_array($json_attempt)?$json_attempt:array();
            if ($attempt >= $this->_config['login_max_attempt']
                && ($exp > $utime)){
                
                $this->set_error('msg_login_attempt'); // Locked Message
                log_message('info', __METHOD__.' -> Locked on other device UPDATE '.$login_attempt. ' to '. $this->_config['login_max_attempt']);

                $json_attempt['att']=$this->_config['login_max_attempt'];
                // TODO, Do I need to update the expiration everytime she failed?
                $json_attempt['exp']=($utime+$this->_config['locked_attempt_exp']);

                //$this->session->set_userdata($login_attempt, json_encode($json_attempt));
            }else{
                if ($exp > 0 && ($exp < $utime)){
                    log_message("debug", __METHOD__.' -> Reseting the attempt: '.(date('Ymd H:i:s',$exp) < date('Ymd H:i:s',$utime)));
                    $json_attempt['att']=1;
                    $json_attempt['exp']=0;      
                    // ToDO, I need to reset the database too.
                }else{
                    $json_attempt['att']=$attempt;
                    if ($attempt>=$this->_config['login_max_attempt']){
                        $json_attempt['exp']=($utime+$this->_config['locked_attempt_exp']);
                        $this->set_error('msg_login_attempt'); // Locked Message
                    }
                }
                $this->set_error( 'login_failed' );
            }
            
            $this->_user_id=$user?$user->id:0;
            log_message('info', __METHOD__.' -> update Attempt for '.$login_attempt. ' to '. $attempt);
            $this->session->set_userdata($login_attempt, json_encode($json_attempt));
            
			return false;
		}else{
            // User matched password but validate if the user made multiple invalid login.
            // Check is user already locked
            if (($user->locked ==1) && ($user->locked_expired > $utime)){
                // Update the session attempt.
                $json_attempt['att']=4; // Validat
                $json_attempt['exp']=($utime+$this->_config['locked_attempt_exp']);
                $this->session->set_userdata($login_attempt, json_encode($json_attempt));
                $this->set_error('msg_login_attempt'); // Locked Message
                return false;
            }
        }




        // Validate teh time login of the user
        if(0 && $user){
            // Disable at reason not valid to control the user/store bussiness time.
            $starttime = mktime($user->shr, $user->smin);
            $endtime = mktime($user->ehr, $user->emin);

            if (!(($utime > $starttime) && ($utime<$endtime))){
                 $this->set_error('login_out_of_time'); // Out ot time.. OT xa?
                 return false; 
            }
        }


        $isAdmin = $this->user_model->has_role($user->id, 'admin');

        if ($isAdmin) log_message ('info','You have admin role.');
        else  log_message ('warning','You DONT have admin role.');
        if ($this->_isLoggedAdmin) log_message ('info','Login As ADMIN');
        else log_message ('warning','Login as USER');

        // Verify the authentication data permission
        if ($this->_isLoggedAdmin && !$isAdmin){
            // User Must not login one Admin page
            $this->audit_model->save(Audit_model::LOGIN, 
                    array('user'=>$user->id,
                        'msg'=>' Login Failed'));
            $this->set_error( 'login_failed' );
            return false;
        }else if(!$this->_isLoggedAdmin && $isAdmin){
            // Admin must not login on user login page.
            $this->audit_model->save(Audit_model::LOGIN, 
                    array('user'=>$user->id,
                        'msg'=>'Login Failed.'));
            $this->set_error( 'login_failed' );
            return false;
        }

        // Reset since she got the right password
        $this->session->unset_userdata($user->account_name);
        
		$session = array(
			'user_id'       => $user->id
            ,'logged'       => $user->logged
			,'user_email'   => $user->email
			,'store_name'   => $user->store_name
			,'account_name' => $user->account_name
			,'logged_in'    => TRUE
			,'p_exp'    => $user->pass_expired
			,'user_'.$this->_config['identity_field'] => $user->{$this->_config['identity_field']}
		);

		foreach( $session_data as $key ){
			$session['user_'.$key] = ( $user->$key ) ? $user->$key : NULL;
		}

		$this->session->set_userdata( $session );
        $update = array();
		if( $remember ){
			$remember_code = $this->phpass->hash(uniqid());
            $update['remember_code']=$remember_code;
        
			$expire = (60*60*24*365*2);
			set_cookie(array(
			    'name'   => 'identity',
			    'value'  => $identity,
			    'expire' => $expire
			));

			set_cookie(array(
			    'name'   => 'remember_code',
			    'value'  => $remember_code,
			    'expire' => $expire
			));
		}
        $this->audit_model->save(Audit_model::LOGIN, 
                array('msg'=>' Login Success',
                    'user'=>$user->id,
                    'account_name'=>$user->account_name,
                    ));
        
        //$update['login_expired']=time()+60*30;
        //$update['login_locked']=1;
        $update = array_merge($update, $this->activateCurrentLogin());
        $this->user_model->update($user->id, $update);
        
		return true;
	}

	private function login_remembered()
	{
		$identity = get_cookie('identity');
		$code 	  = get_cookie('remember_code');
		$user = $this->user_model->get_by( array($this->_config['identity_field'] => $identity) );
		if( $user && $user->remember_code === $code )
		{
			$session = array(
				'user_id' => $user->id
				,'logged_in'=> TRUE
				,'user_'.$this->_config['identity_field'] => $user->{$this->_config['identity_field']}
			);
			$this->session->set_userdata($session);
		}
	}

	/**
	 * logout
	 *
	 * @access public
	 * @return bool
	 **/
	public function logout()
	{
        if ($this->logged_in()){
            $update = $this->deactivateCurrentLogin();
            $update['last_activity'] = 0;
            
            $user_id=$this->session->userdata('user_id');
            $this->user_model->update($user_id, $update);
            $this->audit_model->save(Audit_model::LOGOUT, 
                    array('msg'=>' Logout','user'=>$user_id));
            
            
            // Delete All cookies
//            if ($_COOKIE)foreach($_COOKIE as $k => $v){
//                // TODO, Do I really need to delete all?
//                delete_cookie($k);
//            }
        }
        
		$this->session->sess_destroy();
		delete_cookie('identity');
		delete_cookie('remember_code');
        delete_cookie('t_searchinfo');
		$this->session->sess_create();
        
        
		return( TRUE === $this->session->userdata('logged_in') ) ? false : true;
	}

	/**
	 * is the user logged in?
	 *
	 * @access public
	 * @return bool
	 **/
	public function logged_in()
	{
		return (bool) $this->session->userdata('logged_in');
	}

	/**
	 * Send password reset
	 *
	 * @access public
	 * @param string
	 * @return bool
	 **/
	public function send_password_reset( $identity )
	{
		$user = $this->user_model->get_user( $identity );

		if( ! $user ){
			$this->set_error( 'reset_user_not_found' );
			return false;
		}else if(!$user->status){
            // Disabled user not able not able re request new password
            // Please let admin to update
			$this->set_error( 'account_inactive' );
			return false;            
        }
        
        $time = time();
        // Reset the attempt every 24 hrs.
        if (($time - $user->reset_expired) > self::PASSWORD_EXPIRY){
            // Expire na, start to 1 na ulit yung reset.
        }else if (($user->reset_attempt >= $this->_config['reset_attempt'])
            && ($user->reset_expired > $time) ){
			$this->set_error( 'msg_login_reset' );
			return false;            
        }
        
            
        // Wins mode to set new password instead of token.
        $newPassword = $this->random_password();
        
		$reset_code = $this->_reset_code();
		$update = array(
			'reset_code' => $reset_code
			,'reset_time'=>	time()
            ,'password' => $this->phpass->hash($newPassword)
            ,'logged' => 0 // Force him to change his password
            ,'locked' => 0 // only unlocked when you as new password.
            ,'reset_expired' => $time // One way to check if need to reset the counter.
		);

        if ((($user->reset_attempt>=$this->_config['reset_attempt']) && 
                ($user->reset_expired < $time)) || 
                (($time - $user->reset_expired) > self::PASSWORD_EXPIRY)){
            $update['reset_attempt'] = 1; // reset it to 1 as you send another request
        }else{
            // I will increment  every time he/she attempt to send request.
            $update['reset_attempt'] = $user->reset_attempt+1;
        }
        
        // set the expiration for teh next attempt to ask passwprd reset.
        if ( $update['reset_attempt'] >= $this->_config['reset_attempt'] ){
            $update['reset_expired'] = $time+$this->_config['reset_attempt_expiration'];
        }
        
		$this->user_model->update( $user->id, $update );

		$data = array(
			'user'	=> $user // I dont understand why he pass the whole object
//			,'account_name'	=> $user->account_name
//			,'reset_code' => $reset_code
			,'new_password' => $newPassword
            //,'reset_expired'=>$time()
		);

		$message = $this->load->view( $this->_config['reset_template'], $data, TRUE );
//        $message = 'Your account reset/token key are found below'.
//                "\nAccount Name: ".$user->account_name.
//                "\nToken: ".$reset_code .
//                "\n\n If the information below not works please try to click/copy url below:\n".
//                site_url('user/resetPassword/'.  urlencode($user->account_name).'/'.  urlencode($reset_code));;
        $this->email->initialize(array('mailtype'=>'html'));
		$this->email->from( $this->_config['admin_mail'], $this->_config['admin_name'] );
        $this->email->to( $user->email );

        //$this->session->set_userdata('reset_email', $user->email);
        $this->email->subject( $this->_config['reset_subject'] );
        $this->email->message( $message );
        $this->session->unset_userdata(strtolower($user->account_name));
        
        return ( $this->email->send() ) ? $user->email : false;

	}

	/**
	 * Check if reset token is valid
	 *
	 * @access public
	 * @param string
	 * @param string
	 * @return bool
     * @deprecated since version number
	 **/
	public function check_reset_token( $identity, $token )
	{
		$user = $this->user_model->get_user( $identity );
		if( !$user )
		{
			$this->set_error( 'reset_user_not_found' );
			return false;
		}

		if( ( time() - $user->reset_time ) > $this->_config['reset_code_validation'])
		{
			$this->set_error( 'reset_token_expired' );
			return false;
		}

		if( $user->reset_code === $token )
		{
			return true;
		}
		$this->set_error( 'reset_token_check_failed' );
		return false;
	}

	/**
	 * Confirm password reset
	 *
	 * @access public
	 * @param string
	 * @param string
	 * @param string
	 * @return bool
     * @deprecated 
	 **/
	public function set_new_password( $identity, $token, $newpass )
	{

		$user = $this->user_model->get_user( $identity );
		if( ! $user OR ! $this->check_reset_token( $identity, $token ) )
		{
			$this->set_error( 'reset_user_not_found' );
			return false;
		}

		$data = array(
			'reset_code' => NULL
			,'reset_time'=> NULL
			,'pass_expired' => time()+2592000 // 30days
            ,$this->_config['password_field'] => $this->phpass->hash( $newpass )
			
		);

		if( $this->user_model->update( $user->id, $data ) )
		{

			$session = array();
			foreach( $user as $k => $v )
			{
				$session[] = $k;
			}
            // Win she must login.
			//$this->login( $identity, $newpass, $session );
			return true;
		}
		else
		{
			return false;
		}
	}

	/**
	 * generate reset code
	 *
	 * @access private
	 * @return string
	 **/
	private function _reset_code()
	{
		$ret = '';
		for( $x = 0; $x < 32; $x++ )
		{
			$chars = array(
				chr( mt_rand( 48, 57 ) )
				,chr( mt_rand( 64, 90 ) )
				,chr( mt_rand( 97, 122 ) )
			);
        	//$ret .= chr( mt_rand( 0, 255 ) );
        	$ret .= $chars[array_rand($chars)];
    	}
    	return $ret;
	}

	/**
	 * Checks if a user has a role
	 *
	 * @access public
	 * @param int
	 * @param string
	 * @return bool
	 **/
	public function has_role( $role, $user_id = NULL )
	{
		if( is_null( $user_id ) )
		{
			$user_id = $this->session->userdata('user_id');
		}
		return (bool) $this->user_model->has_role( $user_id, $role );
	}

    
    /**
	 * Act if user has no access
	 *
	 * @access public
     * @param string $role
     * @param action $actions
	 * @return void
	 * @todo allow to set some actions on denied access
     */
	public function restrict_access( $role, $actions = array() )
	{
		$has_role 	= false;
		switch ( $role )
		{
			case 'guest':
				$has_role = true;
				break;
			case 'logged_in':
				if( $this->logged_in() )
				{
					$has_role = true;
				}
				break;
			case 'user':
				if( $this->logged_in() )
				{
					$has_role = true;
				}
				break;
			default:
				if( $this->logged_in() )
				{
					$has_role = $this->has_role( $role );
				}
				break;
		}
		
		if( ! $has_role )
		{
			if( ! $this->logged_in() )
			{
				//THIS IS DEFAULT
				if( strlen($this->_config['401_login_page']) > 0 )
				{
                    if ($role === 'admin'){
                        redirect('admin/login');
                    }else{
                        redirect( $this->_config['401_login_page'] );
                    }
				}
				else if( strlen($this->_config['401_override']) > 0 )
				{
					redirect( $this->_config['401_override'] );
				}
				else
				{
					show_error('Unauthorized', 401 );
				}
			}
			else
			{
				//THIS IS DEFAULT
				if( strlen($this->_config['401_override']) > 0 )
				{
                    
					redirect( $this->_config['401_override'] );
				}
				else
				{
					show_error('Unauthorized', 401 );
				}
			}
		}
	}
    
    /**
    * Change/set the new password
    */
	public function changePassword( $newpass )
	{
        // 
        if ($this->session->userdata('account_name') == $newpass){

        }


        $this->load->library( array( 'configuration'));
        
        $expiration = $this->configuration->getPasswordExpiration()*self::PASSWORD_EXPIRY;
        log_message('debug', __METHOD__.' - LogExpiration: '.$this->configuration->getPasswordExpiration().'=>'.$expiration);
        
        $expiration += time();
        $encPass = $this->phpass->hash( $newpass );
		$data = array(
            'reset_code' => NULL
            ,'reset_time'=> NULL
            ,'logged' => 1 // Test that user already login
            //,'pass_expired' => time()+$this->configuration->getPasswordExpiration()*60*60*24 // 30days
            ,'pass_expired' => $expiration // For testing Purposes.. set to hours.
            //
            //
            //,'pass_expired' => time()+(60) // 1min
            //,'reset_attempt' => 0
            //,'reset_expired' => 0
            ,$this->_config['password_field'] => $encPass
            );
        log_message("debug", print_r($data, 1));
        log_message("debug", "NewPass: ".$newpass);
        
        $user_id = $this->session->userdata("user_id");
        try{
            // Check the use password can still able to use.
            // Saving, process already the checking of password
            if ($this->UPM->save($user_id, array('plain'=>$newpass,'encrypt'=>$encPass))){
                if( $this->user_model->update($user_id, $data) ){
                    // Update the password use.
                    if ($this->has_role("admin")){
                        redirect('admin/logout'); // login nlng xa ulit.
                    }else{
                        redirect('user/logout'); // login nlng xa ulit.
                    }
                    return true;
                }else{
                    return false;
                }
            }else{
                $this->set_error('user_password_not_usable'); // User cant able to reuse again.
                $this->session->set_flashdata('error', $this->get_message('user_password_not_usable'));
                if ($this->has_role("admin"))
                    redirect('admin/changePassword'); // Balik muna sa change password form
                else
                    redirect('user/changePassword'); // Balik muna sa change password form

                return false;
            }
        }catch (Exception $e){
            $this->set_error('user_password_not_usable'); // User cant able to reuse again.
            $this->session->set_flashdata('error', 'Failed to update you password, please try again and report if persist. :)');
            if ($this->has_role("admin"))
                redirect('admin/changePassword'); // Balik muna sa change password form
            else
                redirect('user/changePassword'); // Balik muna sa change password form
            return false;
        }
        return true;
	}


    /**
     * Set error message
     * 
     * @access
     * @param str $error
     * @param str $search Not yet imple
     * @param str $replace Not yet imple
     */
	private function set_error( $error, $search='', $replace='' )
	{
		$this->_errors[] = $error;
	}
    
    /**
     * Set error message
     * 
     * @access
     * @param str $error
     * @param str $search Not yet imple
     * @param str $replace Not yet imple
     */
	private function set_message( $msg )
	{
		$this->_messages[] = $msg;
	}
            
	public function setIsLoggedAdmin($isAdmin = false)
	{
		$this->_isLoggedAdmin = $isAdmin;
        return $this;
	}


	/**
	 * Get error messages
	 *
	 * @access public
	 * @return array
	 **/
	public function errors()
	{
		foreach ( $this->_errors as $key => $error )
		{
			$this->_errors[$key] = $this->lang->line( $error ) ? $this->lang->line( $error ) : '##' . $error . '##';
		}
		return $this->_errors;
	}
    
	public function messages()
	{
		foreach ( $this->_messages as $key => $msg )
		{
			$this->_messages[$key] = $this->lang->line( $msg ) ? $this->lang->line( $msg ) : '##' . $msg . '##';
		}
		return $this->_messages;
	}

    
    public function get_message($key)
	{
        return $this->lang->line($key) ? $this->lang->line($key) : '##' . $key . '##';
	}

    
    /**
     * 
     * @param str $key
     * @return string
     */
    public function get_config($key)
    {
        return $this->_config[$key];
    }

    public function get_user_id()
    {
        return $this->_user_id;
    }

    private function random_password($length = 30) {
        $alphabet = "abcdefghijklmnopqrstuwxyzABCDEFGHIJKLMNOPQRSTUWXYZ0123456789";
        $pass = array();
        $alphaLength = strlen($alphabet) - 1; //put the length -1 in cache
        for ($i = 0; $i < $length; $i++) {
            $n = rand(0, $alphaLength);
            $pass[] = $alphabet[$n];
        }
        return implode($pass); //turn the array into a string
    }
    
    /**
     * 
     */
    public function get_locked_users(){
       if (isset($_COOKIE['t_ul'])){
            $locked = base64_decode($_COOKIE['t_ul']);
            $json = json_decode($locked, true);            
            return is_array($json)?$json:array();
       }
       return array(); 
    }

    /**
     * 
     * @param int/str $id
     * @param str $name
     * @return string a json string that was encoded in base64
     */
    public function add_locked_user($name, $id=0){
        $lockedusers = $this->get_locked_users();
        $lockedusers[$name]=$id?$id:$this->_user_id;
        $json = json_encode($lockedusers);
        $locked = base64_encode($json);

        return $locked;
    }

    /**
     * Any changes. 
     * @param type $name
     * @param type $id
     * @return type
     */
    public function activateCurrentLogin($isSave=false){
        log_message('debug', 'Start - '.__METHOD__.'('.$this->config->item('sess_expiration').')');
        $update = array();
        //$update['']=1;
        $time = time();
        $expire = $this->configuration->getSessionExpiration()*60+$time;// get from DB
        //$expire=$time+$this->config->item('sess_expiration'); // get from config file
        $update['login_expired']=$expire;
        $update['last_activity']=$time;
        if ($isSave){
            log_message('debug','Update user session('.$this->session->userdata("user_id") .')');
            $this->user_model->update($this->session->userdata("user_id"),$update);
            return true;
        }
        
        return $update;
    }
    
    public function deactivateCurrentLogin($isSave=false){
        
        $update = array();
        $update['login_expired']=0;
        
        if ($isSave){
            // I write this one since login and logout sa saveDB event
            $this->user_model->update( $this->session->userdata("user_id"),$update);
            return true;
        }
        
        return $update;
    }

    
    public function isPasswordExpired(){
        return $this->session->userdata('p_exp')<time();
    }
    
    public function add_locked_expiration($key=''){
        
        $exp = $this->_config[($key?$key:'reset_attempt_expiration')];
        if ($exp < 60){ // 1 min
            return ((int)$exp).' seconds';
        }else if ($exp < 3600){ // 1hour
            return ((int)($exp/60)).' minutes';
        }else if ($exp < 86400){ // Day
            return ((int)($exp/86400)).' hours';
        }else {
            return ((int)($exp/86400)).' days';
        }
    }
    
}
